package main;
import hospital.Hospital;

import java.awt.Dimension;

import java.util.ArrayList;
import java.util.List;

import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.ScrollPaneConstants;

import unit.FireTruck;
import unit.Unit;

import dispatch.*;
import emergency.*;
import emergency.Fire.Size;


public class GUI {
	
	private FacadeOperator facadeOperator;
	private FacadeDispatcher facadeDispatcher;
	private FacadeUnit facadeUnit;
	private FacadeTime facadeTime;
	private Operator ingelogdeOperator = null;
	private Dispatcher ingelogdeDispatcher = null;
	private Unit ingelogdeUnit = null;
	
	/**
	 * @param args
	 */
	
	public GUI(String args[]) {
		World world=new World(args);
		facadeOperator = new FacadeOperator(world);
		facadeDispatcher = new FacadeDispatcher(world);
		facadeUnit = new FacadeUnit(world);
		facadeTime = new FacadeTime(world);
		world.startup();


		//inloggen
		boolean exit=false;
		while(!exit){
			List<String> options = new ArrayList<String>();
			options.add("Operator");
			options.add("Dispatcher");
			options.add("Unit Commander");
			options.add("Advance Time");
			int menu = JOptionQuestion("As who do you want to login?", options);
			switch(menu){
			case 1 :	loginOperator();
						break;
			case 2 :	loginDispatcher();
						break;		
			case 3 :	loginUnitCommander();
						break;	
			case 4 : 	advanceTime();
						break;
			case 5 :	exit=true;
						break;
			default	:	break;
			}
		}
	}

	private void actionDispatcher(){
		boolean exit=false;
		while(!exit){
			List<String> options = new ArrayList<String>();
			options.add("Handle emergency");
			options.add("Inspect emergencies");
			options.add("Revoke unit");
			options.add("Cancel emergency");
			int menu = JOptionQuestion("Welcome "+ingelogdeDispatcher.getName(), options);

			switch(menu){
				case 1: dispatcherHandleEmergency();
						break;
				case 2: dispatcherInspectEmergency();
						break;
				case 3: dispatcherRevokeUnit();
						break;
				case 4: dispatcherCancelEmergency();
						break;
				case 5: setIngelogdeDispatcher(null);
						exit=true;
						break;
						
				default:break;
			}
		}
		
	}

	private void actionOperator(){
		boolean exit=false;
		while(!exit){
			List<String> options = new ArrayList<String>();
			options.add("New emergency");
			options.add("New disaster");
			options.add("Show all emergencies");
			int menu = JOptionQuestion("Welcome "+ingelogdeOperator.getName(), options);
			
			switch(menu){
				case 1: operatorAddEmergency();
						break;
				case 2: operatorAddDisaster();
						break;
				case 3: operatorAlleEmergencies();
						break;
				case 4: setIngelogdeOperator(null);
						exit=true;
						break;
						
				default:break;
			}
		}
		
	}
	


	private void actionUnitCommander(){
		boolean exit=false;
		while(!exit){

			List<String> options = new ArrayList<String>();
			options.add("Pick a hospital");
			options.add("Close emergency");
			options.add("Mark unit broken");
			options.add("Mark unit repaired");
			String boodschap = "Welcome "+ingelogdeUnit.getName();
			if(ingelogdeUnit.getBroken()){
				boodschap+="\nDeze unit is in panne!";
			}
			if(ingelogdeUnit.getEmergency()!=null){
				boodschap+="\nOpdracht: "+ingelogdeUnit.getEmergency();
			}
			int menu = JOptionQuestion(boodschap, options);
			try{
				switch(menu){
					case 1: UCSelectHospital();
							break;
					case 2: UCEndOfEmergency();
							break;
					case 3: UCUnitBroken();
							break;
					case 4: UCUnitRepaired();
							break;
					case 5: setIngelogdeUnit(null);
							exit=true;
							break;
							
					default:break;
				}
			}
			catch(Exception e){
				JOptionPane.showMessageDialog(null, e+": regel "+new Exception().getStackTrace()[0].getLineNumber());
			}
		}
	}
	
	private void advanceTime() {
		int hoeveel = asknumber("hoeveel minuten wil je bijtellen?");
		facadeTime.simulatedTimeBy(hoeveel);
	}
	
	private boolean askBoolean(String vraag){
		Boolean inOrde=false;
		int bool=-1;
		while(!inOrde){
			try{
				bool=JOptionPane.showConfirmDialog(null, vraag, vraag, JOptionPane.YES_NO_OPTION);
				if(bool == JOptionPane.YES_OPTION || bool == JOptionPane.NO_OPTION)
					inOrde=true;
			}
			catch(Exception e){}
		}	
		return bool==JOptionPane.YES_OPTION;
	}
	
	private movement.Location askLocation(){
		Boolean inOrde=false;
		int x=0;
		int y=0;
		while(!inOrde){
			try{
				x = Integer.parseInt(JOptionPane.showInputDialog("Location x-coordinaat"));
				y = Integer.parseInt(JOptionPane.showInputDialog("Location y-coordinaat"));
				inOrde=true;
			}
			catch(Exception e){}
		}	
		return new movement.Location(x,y,"emergency");
	}
	
	private int asknumber(String vraag){
		Boolean inOrde=false;
		
		int x=0;
		while(!inOrde){
			try{
				x = Integer.parseInt(JOptionPane.showInputDialog(vraag));
				inOrde=true;
			}
			catch(Exception e){}
		}	
		return x;
	}
	
	private Severity askSeverity(){
		List<String> options = new ArrayList<String>();
		for(Severity severity:facadeOperator.getSeverityTypes()){
			options.add(severity.toString());
		}
		int menu = JOptionQuestion("How bad/urgent is the emergency?", options);
		return facadeOperator.getSeverityTypes()[menu-1];
	}
	private void dispatcherCancelEmergency(){
		ArrayList<Emergency> emergencies = inspectEmergencies();
		if(emergencies.size()>0){
			ArrayList<String> options = new ArrayList<String>();
			for(Emergency e:emergencies){
				options.add(e.toString());
			}
			int menu = JOptionQuestion("Select the emergency you want to cancel.", options)-1;
			options=new ArrayList<String>();
			try{
				Emergency e = emergencies.get(menu);
				facadeDispatcher.cancelEmergency(e);
			}
			catch(Exception e){
				JOptionPane.showMessageDialog(null, e+": regel "+new Exception().getStackTrace()[0].getLineNumber());
			}
		}
		else
			JOptionPane.showMessageDialog(null, "No emergencies selected.");
	}
	
	private void dispatcherHandleEmergency(){
		String prompt="";
		String input="";
		int menu=-1;
		
		prompt="Which emergency do you want to execute?\nUnits available:\nFiretruck: "+facadeDispatcher.getAantalUnits("firetruck")+"\nAmbulance: "+facadeDispatcher.getAantalUnits("ambulance")+"\nPolicecar: "+facadeDispatcher.getAantalUnits("policecar")+"\n";
		int teller=1;
		ArrayList<Emergency> emergencylist = inspectEmergencies();
		if(emergencylist.size()>0){ 
			for(Emergency e:emergencylist){
				prompt = prompt+"\n"+teller+": \t"+e+"\n";
				try{
					prompt+=printUnits(e.createSuggestion(e.filterUnits(facadeDispatcher.getDispatchCenter().getGarage())));
				}
				catch(IllegalArgumentException ex){
					prompt+="Not enough units available for this emergency";
				}
				teller++;
			}
			Emergency teBehandelenEmergency=null;
			Boolean exit=false;
			while(!exit){
				exit=true;
				try{
					JTextArea test = new JTextArea(prompt);
					JScrollPane scroller = new JScrollPane(test);
					scroller.createVerticalScrollBar();
					scroller.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS );
					Dimension dim = new Dimension(650,600);
					scroller.setPreferredSize(dim);
					
					input = JOptionPane.showInputDialog(scroller);
					menu=Integer.parseInt(input);
					teBehandelenEmergency = emergencylist.get(menu-1);
				}
				catch (Exception e) {
					//foutieve invoer
					exit=false;
				}	
				if (input==null)//cancel
					exit=true;
			}	
			try{
				if(teBehandelenEmergency != null){
					ArrayList<Unit> suggestion = teBehandelenEmergency.createSuggestion(teBehandelenEmergency.filterUnits(facadeDispatcher.getDispatchCenter().getGarage()));
					Boolean respons = askBoolean("Do you want to accept the suggestion? \n\n" + printUnits(suggestion));
					
					if(respons)
						facadeDispatcher.assignAllUnits(teBehandelenEmergency);
					else {
						int totalUnitsNeeded = teBehandelenEmergency.getTotalUnitsNeeded();
						boolean stop = false;
						while(totalUnitsNeeded>0||stop)
						{
							String vraag = "Which units do you want to assign ? \n " +
									"Policecars needed: " + teBehandelenEmergency.getTotalPoliceCarsNeeded() + " \n" +
									"Ambulances needed: " + teBehandelenEmergency.getTotalAmbulancesNeeded()+ " \n" +
									"Firetrucks needed: " + teBehandelenEmergency.getTotalFireTrucksNeeded()+ " \n\n";
							vraag+=teBehandelenEmergency.getUnits();
							vraag+="nog nodig: "+teBehandelenEmergency.getTotalUnitsNeeded();
							
							ArrayList<Unit> units = facadeUnit.getAllAvailableUnits(teBehandelenEmergency);	
							ArrayList<String> options = new ArrayList<String>();
							
							for(Unit u : units)
								options.add(u.getName() + " " + u.getCurrentLocation().toString());
		
							int unit = JOptionQuestion(vraag, options)-1;
							Unit u = units.get(unit);
							
							u.assignEmergency(teBehandelenEmergency);
							
							totalUnitsNeeded = teBehandelenEmergency.getTotalUnitsNeeded();
							if(totalUnitsNeeded>0)
								stop=askBoolean("add another unit?");
						}
					}
				}
				
			}
			catch(Exception e){
				JOptionPane.showMessageDialog(null, "This emergency can't be dispatched automatically.");
				JOptionPane.showMessageDialog(null, e+": regel "+new Exception().getStackTrace()[0].getLineNumber());
			}
		}
		else
			JOptionPane.showMessageDialog(null, "No emergency selected");
	}
	
	private void dispatcherInspectEmergency(){
		ArrayList<String> options = new ArrayList<String>();
		ArrayList<Emergency> emergencies = inspectEmergencies();
		if(emergencies.size()>0){
			for(Emergency e:emergencies){
				options.add(e.toString());
			}
			int menu = JOptionQuestion("Welke emergency wil je zien?", options)-1;
			try{
				JOptionPane.showMessageDialog(null, this.giveEmergencyInfo(emergencies.get(menu)));
			}
			catch(IndexOutOfBoundsException e){}
		}
		else
			JOptionPane.showMessageDialog(null, "No emergency selected!");
	}
	
	private void dispatcherRevokeUnit(){
		ArrayList<Emergency> emergencies = inspectEmergencies();
		if(emergencies.size()>0){
			ArrayList<String> options = new ArrayList<String>();
			for(Emergency e:emergencies){
				options.add(e.toString());
			}
			int menu = JOptionQuestion("Select an emergency from which you want to revoke a unit", options)-1;
			options=new ArrayList<String>();
			try{
				Emergency e = emergencies.get(menu);
				for(Unit u:e.getUnitsClone()){
					options.add(u.toString());
				}
				menu = JOptionQuestion("Unit to revoke", options)-1;
				try {
					facadeDispatcher.revokeUnit(e.getUnits().get(menu));
					JOptionPane.showMessageDialog(null, "unit revoked");
				} catch (IllegalAccessException e1) {
					JOptionPane.showMessageDialog(null, "unit was not revoked");
				}
				
			}
			catch(Exception e){}
		}
		else
			JOptionPane.showMessageDialog(null, "No emergencies selected.");
	}
	
	private String giveEmergencyInfo(Emergency e){
		String str="";
		str += e.getClass()+"\n\n";
		str += e.getStateName()+"\n";
		for(Unit u:e.getUnitsClone()){
			str+="\n\n"+u.toString();
		}
		
		return str;
	}
	
	@SuppressWarnings("unused")
	private String giveUnitInfo(Unit u){
		String str="";
		str += u.getName()+"("+u.getClass()+")\n";
		str += "\n";
		str += "Location: "+u.getCurrentLocation()+"\n";
		str += "Snelheid: "+u.getSpeed()+"km/u\n";
		str += "\n";
		if(u.isAssigned()){
			str += "Handles an emergency atm!\n";
			str += u.getEmergency().toString();
		}
		else{
			str += "Is not handling an emergency.";
		}
		return str;
	}	
	
	
	private ArrayList<Emergency> inspectEmergencies(){
		boolean exit=false;
		ArrayList<String> options=new ArrayList<String>();
		
		options.add("Recorded");
		options.add("In progress");
		options.add("Completed");
		options.add("Canceled");

		ArrayList<Emergency> emergencylist = new ArrayList<Emergency>();
		int menu = 0;
		while(!exit){
			exit=true;
			menu = JOptionQuestion("Which kind of emergency do you want to handle?", options);
			try{
				switch(menu){
				case 1: emergencylist = facadeDispatcher.getDispatchCenter().getEmergencyboard().getEmergenciesRecorded();
						break;
				case 2: emergencylist = facadeDispatcher.getDispatchCenter().getEmergencyboard().getEmergenciesInProgress();
					break;
				case 3: emergencylist = facadeDispatcher.getDispatchCenter().getEmergencyboard().getEmergenciesCompleted();
					break;
				case 4: emergencylist = facadeDispatcher.getDispatchCenter().getEmergencyboard().getEmergenciesCancelled();
					break;
				default:break;
				}				
			}
			catch (Exception e) {
				
				//foutieve invoer
				exit=false;
			}	
		}	
		
		return emergencylist;
	}
	
	private ArrayList<Emergency> inspectEmergenciesUnhandled()throws Exception{
		boolean exit=false;
		ArrayList<String> options=new ArrayList<String>();
		
		options.add("Recorded");
		options.add("In progress");

		ArrayList<Emergency> emergencylist = new ArrayList<Emergency>();
		int menu = 0;
		while(!exit){
			exit=true;
			menu = JOptionQuestion("Which kind of emergency do you want to handle?", options);
			try{
				switch(menu){
				case 1: emergencylist = facadeDispatcher.getDispatchCenter().getEmergencyboard().getEmergenciesRecorded();
						break;
				case 2: emergencylist = facadeDispatcher.getDispatchCenter().getEmergencyboard().getEmergenciesInProgress();
						break;
				case 3: throw new Exception("exit");
				default:break;
				}				
			}
			catch (Exception e) {
				//foutieve invoer
				if(e.getMessage().equals("exit"))
					throw new Exception("exit");

				exit=false;
			}	
		}	
		
		return emergencylist;
	}
	
	private int JOptionQuestion(String vraag, List<String> options){
		vraag+="\n";
		int teller=1;
		for(String option:options){
			vraag+="\n"+teller+": "+option;
			teller++;
		}
		vraag+="\n"+teller+": Close";
		int antwoord=-1;
		String bf = "";
		while(antwoord<=0 || antwoord>teller){
			try{
				bf=JOptionPane.showInputDialog(vraag);
				if(bf==null) //cancel
					antwoord=teller;
				else
					antwoord=Integer.parseInt(bf);
				if(antwoord>teller || antwoord<=0)
					JOptionPane.showMessageDialog(null, "Give a number between 1 and "+teller+".");
			}
			catch(Exception e){
				// foutieve invoer
				antwoord=-1;
				JOptionPane.showMessageDialog(null, "Invalid input!");
			}
		}
		return antwoord;
	}
	
	private void loginDispatcher(){
		//login
		List<String> dispatchers = new ArrayList<String>();
		for(Dispatcher d:facadeDispatcher.getDispatchCenter().getDispatchersClone()){
			dispatchers.add(d.getName());	
		}
		int menu = JOptionQuestion("Dear dispatcher, what's your name?", dispatchers);
		if(menu==dispatchers.size()+1){
			//terug naar hoofdmenu
		}
		else{
			setIngelogdeDispatcher(facadeDispatcher.getDispatchCenter().getDispatcher(dispatchers.get(menu-1)));
			actionDispatcher();
		}	
	}

	private void loginOperator(){
		//login
		List<String> operators = new ArrayList<String>();
		for(Operator o:facadeOperator.getDispatchCenter().getOperatorsClone()){
			operators.add(o.getName());	
		}
		int menu = JOptionQuestion("Dear operator, what's your name?", operators);
		if(menu==operators.size()+1){
			//terug naar hoofdmenu
		}
		else{
			setIngelogdeOperator(facadeOperator.getDispatchCenter().getOperator(operators.get(menu-1)));
			actionOperator();
		}
	}

	@SuppressWarnings("unused")
	private void loginUnitCommander(){
		//login
		facadeTime.simulatedTimeBy(0);
		List<String> units = new ArrayList<String>();
		for(Unit u:facadeUnit.getDispatchCenter().getGarage().getUnitsClone()){
			String fireTruckSize = "";
			if(u instanceof FireTruck){
				fireTruckSize = ((FireTruck) u).getMaxFireSize().toString();
			}
			String opdracht="";
			if (u.getEmergency()!=null)
				opdracht+="==> ";
			units.add(opdracht + u.getName()+"     -- "+ u.getCurrentLocation());	
		}
		int menu = JOptionQuestion("Dear unit commmander, what's your name?", units);
		if(menu==units.size()+1){
			//terug naar hoofdmenu
		}
		else{
			setIngelogdeUnit(facadeUnit.getDispatchCenter().getGarage().getUnitsClone().get(menu-1));
			
			actionUnitCommander();
		}
	}

	private void operatorAddDisaster() {
		String beschrijving = JOptionPane.showInputDialog(null,"Geef een korte omschrijving voor de disaster");
		ArrayList<Emergency> emergencies = new ArrayList<Emergency>();
		
		
		int menu;
		String input=null;
		ArrayList<Emergency> emergencylist=null;
			Boolean exit=false;
			while(!exit){
				try{
					try{
						emergencylist = inspectEmergenciesUnhandled();
					}
					catch(Exception e){
						exit=true;
					}
					if(!exit)
					{
						String prompt="Welke emergencies wil je samenbundelen tot een disaster?\n";
						int teller=1;
						for(Emergency e:emergencylist){
							prompt = prompt+"\n"+teller+": \t"+e;
							teller++;
							if(emergencies.contains(e)){
								prompt+=" (TOEGEVOEGD)";
							}
							prompt+="\n";
						}
						
						input = JOptionPane.showInputDialog(prompt);
						menu=Integer.parseInt(input);
						if(!emergencies.contains(emergencylist.get(menu-1))){
							emergencies.add(emergencylist.get(menu-1));
						}
					}
					exit=!askBoolean("wil je nog een emergency toevoegen?");
				}
				catch (Exception e) {
					//foutieve invoer
					exit=false;
				}	
				if (input==null)//cancel
					exit=false;
			}	
			
			try{
				facadeOperator.createDisaster(beschrijving, emergencies);
				//facadeDispatcher.assignAllUnits(teBehandelenEmergency);
			}
			catch(Exception e){
				JOptionPane.showMessageDialog(null, e+": regel "+new Exception().getStackTrace()[0].getLineNumber());
			}
	}

	private void operatorAddEmergency(){
		
		List<String> options = new ArrayList<String>();
		options.add("Fire");
		options.add("Robbery");
		options.add("Public Disturbance");
		options.add("Traffic Accident");
		int menu = JOptionQuestion("What's the type of emergency? ", options);
		
		switch(menu){
		case 1: operatorAddFire();
				break;
		case 2: operatorAddRobbery();
				break;
		case 3: operatorAddPublicDisturbance();
				break;
		case 4: operatorAddTrafficAccident();
				break;
		}

	}
	
	private void operatorAddFire() {
		try{
			facadeOperator.createFire(askLocation(), askSeverity(), Size.LOCAL, askBoolean("Is it a chemical fire?"), asknumber("Howmany people are involved?"), asknumber("Howmany people are injured?"));
		}
		catch(Exception e){
			JOptionPane.showMessageDialog(null, e+":regel "+new Exception().getStackTrace()[0].getLineNumber());
		}
		
	}
	
	private void operatorAddPublicDisturbance() {
		try{
			facadeOperator.createPublicDisturbance(askLocation(), askSeverity(), asknumber("Howmany people are involved?"));
		}
		catch(Exception e){
			JOptionPane.showMessageDialog(null, e+": regel "+new Exception().getStackTrace()[0].getLineNumber());
		}		
	}
	
	private void operatorAddRobbery() {
		try{
			facadeOperator.createRobbery(askLocation(), askSeverity(), askBoolean("Are they armed?"), askBoolean("Is it in progress?"));
		}
		catch(Exception e){
			JOptionPane.showMessageDialog(null, e+": regel "+new Exception().getStackTrace()[0].getLineNumber());
		}
	}
	
	private void operatorAddTrafficAccident() {
		try{
			facadeOperator.createTrafficAccident(askLocation(), askSeverity(), asknumber("Howmany cars are involved?"), asknumber("Howmany people are injured?"));
		}
		catch(Exception e){
			JOptionPane.showMessageDialog(null, e+": regel "+new Exception().getStackTrace()[0].getLineNumber());
		}
	}


	private void operatorAlleEmergencies(){
		String prompt = "All emergencies:\n";
		for(Emergency em:facadeOperator.getDispatchCenter().getEmergencyboard().getEmergencies()){
			prompt = prompt + "\n" + em;
		}
		JOptionPane.showMessageDialog(null, prompt);
	}
	
	private String printUnits(ArrayList<Unit> units){
		String str="";
		for(Unit u:units){
			str+=u.showInfo();
			str+="\n";
		}
		return str;
		
	}
	
	private void setIngelogdeDispatcher(Dispatcher d){
		this.ingelogdeDispatcher = d;
		this.ingelogdeOperator = null;
		this.ingelogdeUnit = null;
	}
	
	
	private void setIngelogdeOperator(Operator o){
		this.ingelogdeDispatcher = null;
		this.ingelogdeOperator = o;
		this.ingelogdeUnit = null;
	}
	
	private void setIngelogdeUnit(Unit u){
		this.ingelogdeDispatcher = null;
		this.ingelogdeOperator = null;
		if(u!=null){
			this.ingelogdeUnit = facadeUnit.getDispatchCenter().getGarage().getUnit(u.getName());
		}
		else 
			this.ingelogdeUnit = null;
	}
	
	private void UCEndOfEmergency(){
		try{
			facadeUnit.finishEmergency(ingelogdeUnit);
		}
		catch(Exception e){
			JOptionPane.showMessageDialog(null, e+": regel "+new Exception().getStackTrace()[0].getLineNumber());
		}
	}
	
	private void UCSelectHospital(){

		List<String> options = new ArrayList<String>();
		for(Hospital h:facadeUnit.getHospitals(ingelogdeUnit.getCurrentLocation())){
			options.add(h.getName());
		}
		int menu = JOptionQuestion("Select a hospital", options);
		facadeUnit.assignHospital(ingelogdeUnit, facadeUnit.getHospitals(ingelogdeUnit.getCurrentLocation()).get(menu-1));
		
	}
	
	private void UCUnitBroken(){
		try{
			facadeUnit.breakDown(ingelogdeUnit);
		}
		catch(Exception e){
			JOptionPane.showMessageDialog(null, e+": regel "+new Exception().getStackTrace()[0].getLineNumber());
		}
	}
	
	private void UCUnitRepaired(){
		try{
			facadeUnit.repair(ingelogdeUnit);
		}
		catch(Exception e){
			JOptionPane.showMessageDialog(null, e+": regel "+new Exception().getStackTrace()[0].getLineNumber());
		}
	}

}